#include <stdlib.h>
#include <string.h>
#include <types.h>
#include <bitops.h>
#include <device.h>
#include <printk.h>
#include "board.h"
#include "os.h"
#include <syserr.h>
#include "dev.h"
#include "settings.h"

#ifdef configUSING_ISL29026


typedef struct
{
    uint16_t dot_x;
		uint16_t dot_y;
} lux_dot_t;



struct isl29026_data
{
    struct i2c_bus_device *i2c_bus;
};

static struct isl29026_data isl29026_data;

static int isl29026_read_reg(struct i2c_bus_device *i2c_bus, uint8_t reg, uint8_t *values, size_t length)
{
    struct i2c_msg msgs[2];

    msgs[0].addr  = ISL29026_ADDR;
    msgs[0].flags = I2C_WR;
    msgs[0].buf   = &reg;
    msgs[0].len   = 1;

    msgs[1].addr  = ISL29026_ADDR;
    msgs[1].flags = I2C_RD; /* Read from slave */
    msgs[1].buf   = (uint8_t *)values;
    msgs[1].len   = length;

    if (i2c_transfer(i2c_bus, msgs, 2) == 2)
        return 0;

    return -EIO;
}

static int isl29026_write_reg(struct i2c_bus_device *i2c_bus, uint8_t reg, uint8_t *values, size_t length)
{
    uint8_t tmp[0x20];
    struct i2c_msg msgs[1];
    
    tmp[0] = reg;
    memcpy(&tmp[1], values, length);

    msgs[0].addr  = ISL29026_ADDR;
    msgs[0].flags = I2C_WR;
    msgs[0].buf   = tmp;
    msgs[0].len   = length+1;

    if (i2c_transfer(i2c_bus, msgs, 1) == 1)
        return 0;

    return -EIO;
}

void isl29026_reset(const struct isl29026_data *isl29026)
{
    uint8_t i;
    uint8_t reg[] = { CONFIGURE, TEST_MODE2, TEST_MODE1, TEST_MODE2, CONFIGURE, INTERRUPT};
    uint8_t value[] = {COMMEND_RESET, 0x29, 0x00, 0x00, COMMEND_LIGHT, COMMEND_NOINTERRUPT};

    for(i = 0; i < sizeof(reg); i++)
    {
        isl29026_write_reg(isl29026->i2c_bus, reg[i], &value[i], 1);
    }
}

static size_t isl29026_get_sensor_value(device_t *dev, off_t pos, void *buffer, size_t size)
{
    struct isl29026_data *isl29026 = (struct isl29026_data *)dev->user_data;
	  uint8_t config, data1, data2;
    
    err_t err = isl29026_read_reg(isl29026->i2c_bus, CONFIGURE, &config, 1);
	 //log_d( "isl29026 not found=%d!\n", config);
    if (err < 0) 
			return (0);
    if(COMMEND_LIGHT != config)  //error, need reset!
    {
				//log_d( "isl29026 reset!\n");
        isl29026_reset(isl29026);
        return 0;
    }
    err = isl29026_read_reg(isl29026->i2c_bus, ALSIR_DT1, &data1, 1);
    if (err < 0) return (0);
    err = isl29026_read_reg(isl29026->i2c_bus, ALSIR_DT2, &data2, 1);
    if (err < 0) return (0);

    uint16_t value = data1 + ((data2 & 0x0F) << 8);
    //value = value/2 + value/50 + value/500;
    value *= RANGE1;
    put_le_val(value, buffer, 2);

    return 2;
}

static const struct device_ops isl29026_dev_ops =
{
    .read = isl29026_get_sensor_value,
};

static struct device isl29026_dev;

err_t isl29026_init(const char *i2c_bus_name)
{
    struct i2c_bus_device *i2c_bus = (struct i2c_bus_device *)device_find(i2c_bus_name);
    if (i2c_bus == NULL)
    {
        log_d( "\ni2c_bus %s for isl29026 not found!\n", i2c_bus_name);
        return -ENOSYS;
    }

    if (device_open(&i2c_bus->parent, NULL) != 0)
    {
       log_d("\ni2c_bus %s for isl29026 opened failed!\n", i2c_bus_name);
        return -EIO;
    }
    isl29026_data.i2c_bus  = i2c_bus;
    isl29026_dev.ops = &isl29026_dev_ops;
    isl29026_dev.user_data = &isl29026_data;

    isl29026_reset(&isl29026_data);

    device_register(&isl29026_dev, "i29026", 0);
    return 0;
}


static lux_dot_t  lux_standard_tab[] =
{
	{0	,0    },
	{2	,5    },
	{37	,80   },
	{41	,86   },
	{42	,95   },
	{47	,108  },
	{59	,141  },
	{62	,175  },
	{75	,186  },
	{103,	265 },
	{119,	317 },
	{150,	400 },
	{163,	433 },
	{224,	628 },
	{256,	725 },
	{261,	712 },
	{263,	732 },
	{272,	739 },
	{324,	1015},
	{334,	1084},
	{336,	935 },
	{337,	935 },
	{342,	1052},
	{351,	1112},
	{408,	1286},
	{448,	1348},
	{451,	1465},
	{462,	1385},
	{465,	1506},
	{507,	1572},
	{512,	1570},
	{718,	2190},
	{806,	2490},
	{996,	3010},
	{1015, 3090 },
	{2000, 5000 },
};


static uint16_t illumination_calc(uint16_t value)
{
  	int i;
	  double x,y,re;
    for (i = 0; i < array_size(lux_standard_tab); i++) 
    {
        if (lux_standard_tab[i].dot_x >= value)
				{
					if(i < (array_size(lux_standard_tab)-1))
					{
						x = (lux_standard_tab[i+1].dot_x) - (lux_standard_tab[i].dot_x);
						y = (lux_standard_tab[i+1].dot_y) - (lux_standard_tab[i].dot_y);
						re = lux_standard_tab[i].dot_y + (y/x)*(value - lux_standard_tab[i].dot_x);
						return re;
					}
				}
    }
    return 5000;
}


void get_illumination(void)
{
	uint8_t val[2],b;
	int data = 0,value = 0; 
	size_t size = device_read(dev_isl2906, 0, val, sizeof(val));
	if (size != sizeof(val))
	{
		log_d("isl29026 read ERROR!\n");
	}
	else
	{
		data  = (val[1] << 8)|val[0];
		value	= illumination_calc(data);
		//data  =  0.522 * data;//value = 0.522 * ret;
		b 		= bcd2bin(setting.dev_infor.compensate_percent);
		value = value *((double)b/10.00);
		sensor_status.cur_lux = data;
		log_d( "isl29026 data : %d,%d\n", data,value);
	}
}

#endif
